package com.xu.cloud.common.util;

import lombok.Data;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * @author xuguan
 * @since 2024/6/14
 */
public class XmlUtil {

    public static String toXmlString(Object obj) {
        return toXmlString(obj, newJaxbContext(obj.getClass()));
    }

    public static <T> T parseObj(String xmlStr, Class<T> cls) {
        return parseObj(xmlStr, cls, newJaxbContext(cls));
    }

    public static String toXmlString(Object obj, JAXBContext jaxbContext) {
        if (Objects.isNull(obj)) {
            return null;
        }

        try (final StringWriter writer = new StringWriter()) {
            final Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name());
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            marshaller.marshal(obj, writer);

            return writer.toString();
        } catch (JAXBException | IOException e) {
            throw new RuntimeException("xml格式化异常", e);
        }
    }

    public static <T> T parseObj(String xmlStr, Class<T> cls, JAXBContext jaxbContext) {
        try (final StringReader reader = new StringReader(xmlStr)) {
            final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            return cls.cast(unmarshaller.unmarshal(reader));
        } catch (JAXBException e) {
            throw new RuntimeException("xml解析异常", e);
        }
    }

    private static JAXBContext newJaxbContext(Class<?>... classes) {
        try {
            return JAXBContext.newInstance(classes);
        } catch (JAXBException e) {
            throw new RuntimeException("实例化JAXBContext对象异常", e);
        }
    }

    public static void main(String[] args) {
        final RootRequest<UserTest> rootRequest = new RootRequest<>();
        final RequestBody<UserTest> requestBody = new RequestBody<>();
        final UserTest userTest = new UserTest();
        userTest.setName("xuguan");
        userTest.setAge("18");
        userTest.setSex("1");
        rootRequest.setRequestBody(requestBody);
        requestBody.setBody(userTest);

        final String xmlStr = XmlUtil.toXmlString(rootRequest, newJaxbContext(RootRequest.class, RequestBody.class, UserTest.class));
        System.out.println(xmlStr);

        final RootRequest parseObj = XmlUtil.parseObj(xmlStr, RootRequest.class, newJaxbContext(RootRequest.class, RequestBody.class, UserTest.class));
        System.out.println(parseObj);
    }

    @Data
    @XmlRootElement(name = "xucloud")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class RootRequest<T> {
        private RequestBody<T> requestBody;
    }

    @Data
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class RequestBody<T> {
        @XmlAnyElement(lax = true)
        private T body;
    }

    @Data
    @XmlRootElement(name = "user")
    public static class UserTest {
        private String name;
        private String age;
        private String sex;
    }
}
